using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

using KmlUtils;

namespace StormModelToKMLDB
{
    public class NHCDiscussion : IKml, IComparable<NHCDiscussion>
    {
        #region Events
        public delegate void DiscussionRetrievedHandler(List<NHCDiscussion> discs);
        public event DiscussionRetrievedHandler DiscussionRetrieved;
        #endregion

        #region Private Members
        private DateTime _dateTime;
        private string _id;
        private List<Observation> _forecast;
        private string _entireDiscussion;
        #endregion

        #region Constructors
        public NHCDiscussion(string discussion)
        {
            this._forecast = new List<Observation>();
            this.Parse(discussion);
            this._entireDiscussion = discussion;
        }
        #endregion

        #region IKml Members

        public void WriteTo(System.Xml.XmlTextWriter tw)
        {
            
        }

        #endregion
    
        #region IComparable Members

        public int  CompareTo(NHCDiscussion obj)
        {
            return obj.DateTime.CompareTo(this._dateTime);
            //return this._dateTime.CompareTo(obj._dateTime);
        }

        #endregion

        #region Public Methods / Properties
        public string EntireDiscussion
        {
            get { return _entireDiscussion; }
            set { _entireDiscussion = value; }
        }
        public DateTime DateTime
        {
            get { return _dateTime; }
            set { _dateTime = value; }
        }
        public string Id
        {
            get { return _id; }
            set { _id = value; }
        }
        public List<Observation> Forecast
        {
            get { return _forecast; }
            set { _forecast = value; }
        }

        public static List<NHCDiscussion> ParseNHC(byte[] b)
        {
            List<NHCDiscussion> discs = new List<NHCDiscussion>();

            // Create an ASCII reader from the byte array
            StringReader r = new StringReader(Encoding.ASCII.GetString(b));

            // state 0 = before beg of storm
            // state 1 = inside single storm
            // state 2 = end of storm
            int state = 0;
            String line = "";
            StringBuilder buf = new StringBuilder();
            while ((line = r.ReadLine()) != null)
            {
                // Beginning of a discussion
                if (line.IndexOf("WTNT4") > -1)
                    state = 1;

                // End of a discussion
                if (state == 1 && line.Contains("$$"))
                {
                    buf.Append(line.Trim());
                    // Reset State for a possible new storm
                    state = 0;
                    string single = buf.ToString();

                    // Create an add the storm to our list
                    NHCDiscussion disc = new NHCDiscussion(single);
                    discs.Add(disc);

                    buf.Remove(0, buf.Length);
                }

                // Reading a Single discussion Entry, keep going
                if (state == 1 && line.Length > 0)
                    buf.AppendLine(line.Trim());
            }

            // return our list of parsed Storms
            return discs;
        }

        private void Parse(string s)
        {
            StringReader r = new StringReader(s);
            string line = "";
            int lineCount = 1;
            bool inForecastZone = false;
            while (line != null && (line = r.ReadLine()) != null)
            {
                if(lineCount == 4)
                    this._id = this.ParseID(line);
                if (lineCount == 5)
                    this._dateTime = this.ParseDateTime(line);
                if(line.Contains("FORECAST POSITIONS AND MAX WINDS"))
                    inForecastZone = true;
                if(inForecastZone)
                {
                    if (line.Contains("HR VT") || line.Contains("INITIAL"))
                    {
                        Observation obs = this.ParseObservation(line);
                        if(obs != null)
                            this._forecast.Add(obs);
                    }
                }
                lineCount++;
                
            }
        }

        private Observation ParseObservation(string line)
        {
            Observation o = null;
            int index = line.IndexOf("KT");
            if (index > 0)
            {
                line = line.Substring(0, index);
                //INITIAL      05/2100Z 17.4N  48.5W    40 KT
                //12HR VT     06/0600Z 18.0N  49.9W    45 KT
                //24HR VT     06/1800Z 18.8N  51.9W    50 KT
                //...
                string[] toks = line.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                string sLat = toks[toks.Length - 3];//.Remove(toks[toks.Length - 4].Length-1); // Does not deal with negative (S)
                string sLon = toks[toks.Length - 2];//.Remove(toks[toks.Length - 3].Length - 1); // Does not deal with negative (W)

                int speed = int.Parse(toks[toks.Length - 1]);
                o = new Observation(sLat, sLon);
                o.SHIP = speed;
                o.DSHP = speed;
            }

            return o;
        }

        private DateTime ParseDateTime(string line)
        {
            //500 PM EDT TUE SEP 05 2006
            //1100 AM EDT TUE SEP 05 2006
            DateTime ret = new DateTime();
            try
            {
                string toParse = "";
                string[] toks = line.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);

                // HH
                if (toks[1].Equals("PM"))
                {
                    string sHr = toks[0].Substring(0, toks[0].Length - 2);
                    toParse += (double.Parse(sHr) + 12.0).ToString("00");
                }
                else
                {
                    string sHr = toks[0].Substring(0, toks[0].Length - 2);
                    toParse += (double.Parse(sHr)).ToString("00");
                }

                // MMM
                toParse += toks[4];

                // dd
                toParse += toks[5];

                // yyyy
                toParse += toks[6];

                ret = DateTime.ParseExact(toParse, "HHMMMddyyyy", null);
                //DateTime.ParseExact(tmp.InnerText, "yyyy-MM-ddTHH:mm:ss.fffZ", null);
            }
            catch (Exception)
            {
            }
            return ret;
        }

        private string ParseID(string line)
        {
            string ret = "(";
            try
            {
                string[] toks = line.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                ret += toks[toks.Length - 1];
                ret += ")";
            }
            catch (Exception)
            {
                return "unknown";
            }

            return ret;
        }
        #endregion
    }
}
